#ifndef RoStanzas_h
#define RoStanzas_h


#include <QtXml>


class RoStanzaId
{
private:
    QString data;
public:
    RoStanzaId(const QString & s = QString()): data(s) { }
    bool isNull() const { return data.isEmpty(); }
    const QString & toString() const { return data; }
    bool operator< (const RoStanzaId & other) const { return data < other.data; }
};


class RoStanza:
    public QObject,
    public QDomDocument
{
    Q_OBJECT

public:

    typedef QDomDocument super;

    RoStanza();

    RoStanza(const RoStanza&);

    RoStanza& operator=(const RoStanza& rhs);

    Q_INVOKABLE QString from() const;

    Q_INVOKABLE QString to() const;

    Q_INVOKABLE QString type() const;

    Q_INVOKABLE RoStanzaId id() const;

    Q_INVOKABLE QDomElement body();

    Q_INVOKABLE QString attribute(const QString & name, const QString & defValue = QString()) const;
    Q_INVOKABLE RoStanza & setAttribute(const QString & name, const QString & value);

    Q_INVOKABLE QString bodyAttribute(const QString & name, const QString & defValue = QString()) const;
    Q_INVOKABLE RoStanza & setBodyAttribute(const QString & name, const QString & value);

    Q_INVOKABLE QString bodyText() const;
    Q_INVOKABLE RoStanza & setBodyText(const QString & text);

protected:

    RoStanza(QString tagName, QDomDocument source = QDomDocument());

}; // class RoStanza


class RoErrorStanza:
    public RoStanza
{
    Q_OBJECT

public:

    typedef RoStanza super;

    // см. Ошибки уровня протокола в спецификации
    // Нулевое значение используется для обозначения исключительной ситуации
    enum ErrorType
    {
        BadFormat = 1,
        Conflict,
        ConnectionTimeout,
        InternalError,
        NotAuthorized,
        ResourceConstrained,
        SystemShutdown,
        UnsupportedVersion,
        XmlNotWellFormed,
        // --
        _CriticalErrors,
        // --
        ImproperAddressing,
        InvalidFrom,
        InvalidId,
        RestrictedXml,
        UnsupportedStanzaType,
        // --
        _ErrorTypesCountPlus1
    };
    static const int ErrorTypesCount;

    RoErrorStanza(QDomDocument source = QDomDocument());

    RoErrorStanza(ErrorType errorType);

    Q_INVOKABLE ErrorType errorType() const;

private:

    static QMap<ErrorType, QString> TagNames;
    static QMap<ErrorType, QString> DefaultDescriptions;

    static void init();

}; // class RoErrorStanza


class RoInfoStanza:
    public RoStanza
{
    Q_OBJECT

public:

    typedef RoStanza super;

    explicit RoInfoStanza(QDomDocument source = QDomDocument());

    explicit RoInfoStanza(const QString & name);

    Q_INVOKABLE QString name() const;

}; // class RoInfoStanza


class RoIqStanza:
    public RoStanza
{
    Q_OBJECT
    Q_ENUMS(ErrorType)

public:

    typedef RoStanza super;
    // см. Ошибки уровня приложения в спецификации
    // Нулевое значение используется для обозначения исключительной ситуации
    enum ErrorType
    {
        BadParameters = 1,
        ComponentGone, // эта ошибка в протоколе не описана.
                       // её компонент посылает себе сам, чтобы закрыть диалоги при отваливании респондента
        InternalError,
        MethodUnknown,
        RecipientUnknown,
        RidUnknown,
        SenderUnknown,
        // --
        UserType, // начиная с этого значения можно определять пользовательские типы ошибок
        // --
        _ErrorTypesCountPlus1
    };

    RoIqStanza(QDomDocument source = QDomDocument());

    Q_INVOKABLE static RoIqStanza createRequest(QString to, QString method, QDomDocument argument = QDomDocument(), QString from = "");
    Q_INVOKABLE static RoIqStanza createDatum(QString to, RoStanzaId rid, QDomDocument payload, QString from = "");
    Q_INVOKABLE static RoIqStanza createDatum(QString to, RoStanzaId rid, QString payloadName, QString from = "");
    Q_INVOKABLE static RoIqStanza createResult(QString to, RoStanzaId rid, QDomDocument payload, QString from = "");
    Q_INVOKABLE static RoIqStanza createResult(QString to, RoStanzaId rid, QString payloadName, QString from = "");
    Q_INVOKABLE static RoIqStanza createError(ErrorType errorType, QString to, RoStanzaId rid, QString from = "");
    Q_INVOKABLE static RoIqStanza createError(QString errorType, QString to = "", RoStanzaId rid = RoStanzaId(), QString from = "");

    Q_INVOKABLE QString method() const;

    Q_INVOKABLE RoStanzaId rid() const;

    Q_INVOKABLE QDomDocument argument() const;

    Q_INVOKABLE QDomDocument payload() const;

    Q_INVOKABLE RoStanza & setErrorDescription(QString text);

private:

    static QMap<ErrorType, QString> TagNames;
    static QMap<ErrorType, QString> DefaultDescriptions;

    static void init();

}; // class RoIqStanza


#endif // RoStanzas_h
